package com.springboot.util;

import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.XML;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

/**
 * 	微信支付
 * @author 梁冲
 *
 */
public class WXPaymentTool {

	private static final Logger logger = LoggerFactory.getLogger(WXPaymentTool.class);

	/**
	 * 	统一下单
	 * @param params	微信文档中统一下单中的参数
	 * @param key		api 密钥
	 * @return
	 * @throws JSONException 
	 */
	public static JSONObject requestPayment(SortedMap<Object, Object> params, String key) throws JSONException {
		String sign = createSign(params, key);
		
		// 遍历参数生成xml
		StringBuffer postParams = new StringBuffer();
		postParams.append("<xml>");
		for (Entry<Object, Object> entry : params.entrySet()) {
			postParams.append("<" + entry.getKey() + ">" + entry.getValue() + "</" + entry.getKey() + ">");
		}
		postParams.append("<sign>" + sign + "</sign>");
		postParams.append("</xml>");

		logger.info("发起支付请求传递的参数：{}", postParams.toString());
		
		String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
		
		String result = HttpConnectionUtil.requestMethod(HttpConnectionUtil.HTTP_POST, url, postParams.toString(), HttpConnectionUtil.CONTENT_TYPE_TEXT_HTML);
		org.json.JSONObject json = XML.toJSONObject(result);

		logger.info("发起微信支付响应:{}",result);

		JSONObject resultJson = new JSONObject();
		org.json.JSONObject xmljson = json.getJSONObject("xml");
		if (xmljson.getString("return_code").equals("SUCCESS")) {
			Long timeStamp = System.currentTimeMillis();
			String nonce_str = UUID.randomUUID().toString().replace("-", "").toUpperCase();
			SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
			parameters.put("appId", params.get("appid"));
			parameters.put("timeStamp", timeStamp.toString());
			parameters.put("nonceStr", nonce_str);
			parameters.put("signType", "MD5");
			parameters.put("package", "prepay_id=" + xmljson.getString("prepay_id"));
			String paySign = createSign(parameters, key);
			resultJson.put("timeStamp", timeStamp.toString());
			resultJson.put("signType", parameters.get("signType"));
			resultJson.put("nonceStr", parameters.get("nonceStr"));
			resultJson.put("appId", params.get("appid"));
			resultJson.put("paySign", paySign);
			resultJson.put("package", parameters.get("package"));
		} else {
			resultJson.put("return_code", "FAIL");
			resultJson.put("return_msg", xmljson.getString("return_msg"));
		}
		return resultJson;
	}


	/**
	 *  查询微信订单状态
	 * @param params
	 * @param key
	 * @return
	 * @throws JSONException 
	 */
	public static void queryOrderState(SortedMap<Object, Object> params, String key) throws JSONException {
		String sign = createSign(params, key);

		// 遍历参数生成xml
		StringBuffer postParams = new StringBuffer();
		postParams.append("<xml>");
		for (Entry<Object, Object> entry : params.entrySet()) {
			postParams.append("<" + entry.getKey() + ">" + entry.getValue() + "</" + entry.getKey() + ">");
		}
		postParams.append("<sign>" + sign + "</sign>");
		postParams.append("</xml>");

		String url = "https://api.mch.weixin.qq.com/pay/orderquery";

		String result = HttpConnectionUtil.requestMethod(HttpConnectionUtil.HTTP_POST, url, postParams.toString(), HttpConnectionUtil.CONTENT_TYPE_TEXT_HTML);
		org.json.JSONObject json = XML.toJSONObject(result);

		logger.info("查询微信订单信息:{}",result);

		JSONObject resultJson = new JSONObject();
		org.json.JSONObject xmljson = json.getJSONObject("xml");
		if (xmljson.getString("return_code").equals("SUCCESS")) {


		} else {


		}
	}
	
	
	public static void main(String[] args) {

		SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
		parameters.put("appid", "wx945bedf330bd40a4");
		parameters.put("mch_id", "1532517381");
		parameters.put("nonce_str", "43377A8EB1B449CEBA9882A8084979E8");
		parameters.put("body", "永成医美-订单支付");
		parameters.put("spbill_create_ip", "114.250.150.10");
		parameters.put("notify_url", "https://text.tyc-bj.cn/yc/api/shopp/payment/payNotify");
		parameters.put("trade_type", "JSAPI");
		parameters.put("out_trade_no", "FW-20190626-00005-YY9");
		parameters.put("total_fee", 9);
		parameters.put("openid", "o0LFo5LqM5aKseKd_li5PH6_ba0I");
		try {

			JSONObject jsonObject = requestPayment(parameters, "U3pFoGx1i3sclqNbx2LH8aoSJmV29901");

			System.err.println(jsonObject.toJSONString());

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 	退款
	 * @return
	 * @throws Exception 
	 */
	@SuppressWarnings("deprecation")
	public static String refund(SortedMap<Object, Object> parameters, String appkey) throws Exception {
		String sign = createSign(parameters, appkey);
		
		// 遍历参数生成xml
		StringBuffer postParams = new StringBuffer();
		postParams.append("<xml>");
		for (Entry<Object, Object> entry : parameters.entrySet()) {
			postParams.append("<" + entry.getKey() + ">" + entry.getValue() + "</" + entry.getKey() + ">");
		}
		postParams.append("<sign>" + sign + "</sign>");
		postParams.append("</xml>");
		
		// 指定读取证书格式为PKCS12
		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		// 读取本机存放的PKCS12证书文件
		InputStream stream = WXPaymentTool.class.getClassLoader().getResourceAsStream("pay/apiclient_cert.p12");
		//FileInputStream stream = new FileInputStream(new File("D:/yongcheng/apiclient_cert.p12"));
		StringBuffer result = new StringBuffer();
		try {
			// 指定PKCS12的密码(商户ID)
			keyStore.load(stream, parameters.get("mch_id").toString().toCharArray());
		} catch (Exception e) {
			stream.close();
		}
		SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, parameters.get("mch_id").toString().toCharArray()).build();
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		
		try {

			HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
			httpPost.setHeader("Content-Type", "text/xml; charset=UTF-8");
			
			StringEntity entityParams = new StringEntity(postParams.toString(), "UTF-8");
			entityParams.setContentType("text/xml");
			httpPost.setEntity(entityParams);

			CloseableHttpResponse response = httpclient.execute(httpPost);
			try {
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
					String text;
					while ((text = bufferedReader.readLine()) != null) {
						result.append(text);
					}
				}
				EntityUtils.consume(entity);
			} finally {
				response.close();
			}
		} finally {
			httpclient.close();
		}
		return result.toString();
	}
	
	
	/**
	 * 	字典序排列参数并生成 sign
	 * @param parameters
	 * @param key
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static String createSign(SortedMap<Object, Object> parameters, String key) {
		StringBuffer sb = new StringBuffer();
		StringBuffer sbkey = new StringBuffer();
		// 所有参与传参的参数按照accsii排序（升序）
		Set es = parameters.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Entry entry = (Entry) it.next();
			String k = (String) entry.getKey();
			Object v = entry.getValue();
			// 空值不传递，不参与签名组串
			if (null != v && !"".equals(v)) {
				sb.append(k + "=" + v + "&");
				sbkey.append(k + "=" + v + "&");
			}
		}
		sbkey = sbkey.append("key=" + key);
		return MD5Util.MD5(sbkey.toString());
	}
}
